//
//  BRUDPService.m
//  ZhuShou
//
//  Created by Dejun Liu on 15/11/6.
//  Copyright © 2015年 jw. All rights reserved.
//

#import "BRUDPService.h"
#import "ZSUDPClient.h"
#import "ZSUDPServer.h"

@interface BRUDPService ()

@property (nonatomic,strong) ZSUDPServer *server;

/**
 *  消息队列用于重试发送：发送完成就从这里移除，不再重试发送；atomic保证数组线程安全
 */
@property (atomic,strong) NSMutableArray *messageQueue;

/**
 *  轮询时钟
 */
@property (nonatomic,strong) NSTimer *timer;

@end

@implementation BRUDPService

JW_SINGLETON_IMPL(BRUDPService)

- (instancetype)init
{
    self = [super init];
    if (self) {
        //消息队列，用于重试发送消息
        self.messageQueue = [NSMutableArray array];
        
        //轮询时间
        [self performSelectorInBackground:@selector(startTimer) withObject:nil];
        
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(finishOneMessageResponse:) name:BRMessageNotificationDidFinishedProcessResponse object:nil];
        
        //server
        self.server = [[ZSUDPServer alloc] init];
        [self.server startUDPServer:YES port:kUDPLocalServerPort];
        @weakify(self);
        self.server.eventCallBack = ^(UDPServerEventType event,
                                       GCDAsyncUdpSocket *sock,
                                       NSData *toAddress,
                                       NSData *fromAddress,
                                       NSData *receiveData,
                                       NSError *error,
                                       long tag,
                                       id filterContext){
            switch (event) {
                case UDPServerEventTypeDidReceiveData:
                {
                    @strongify(self);
                    [self recievedData:receiveData];
                }
                    break;
                    
                default:
                    break;
            }
        };
//        for (int i=0;i<100; i++) {
//            NSDictionary *dic = @{@"hello":@"2"};
//            [self sendMessageString:[dic JSONString] cmd:0x0102 timeout:3 retryCount:3 response:^(BRMessageResponseType type, NSInteger retryCount, NSString *jsonString) {
//                DLog(@"response:%d %d %@",type,retryCount,jsonString);
//            }];
//        }
    }
    return self;
}

- (void)sendMessageDictionary:(NSDictionary *)params
                          cmd:(UInt16) cmd
                      timeout:(NSTimeInterval) second
                   retryCount:(NSInteger) count
                     response:(ResponseBlock) completion
{
    [self sendMessageString:[params JSONString]  cmd:cmd timeout:second retryCount:count response:^(BRMessageResponseType type, NSInteger retryCount, id responseObj) {
        if (responseObj != nil && [responseObj isKindOfClass:[NSString class]]) {
            DLog(@"%@",responseObj);
            completion(type,retryCount,[responseObj JSONObject]);
        }else
        {
            completion(type,retryCount,responseObj);
        }
    }];
}

- (void)sendMessageString:(NSString *)string
                      cmd:(UInt16) cmd
                  timeout:(NSTimeInterval) second
               retryCount:(NSInteger) count
                 response:(ResponseBlock) completion
{
    BRMessage *msg = [BRMessage messageWithCmd:cmd msg:string];
    msg.timeOut = second;
    msg.maxRetryCount = count;
    msg.responseBlock = completion;
    [self sendMessageObjectAndAddMessageQueue:msg];
}

/**
 *  用于第一次发送消息
 *
 *  @param msg 消息
 */
- (void)sendMessageObjectAndAddMessageQueue:(BRMessage *)msg
{
    [self.messageQueue addObject:msg];
    [self sendMessageObject:msg];
}
/**
 *  用于重试发送消息
 *  不添加到队列中，仅仅发送消息;
 *
 *  @param msg 消息对象
 */
- (void)sendMessageObject:(BRMessage *)msg
{
    msg.sendDate = [NSDate date];
    NSData *data = [msg getPackageData];
    [self.server sendData:data hostIP:kUDPRemoteServerIP port:kUDPRemoteServerPort timeout:2 tag:0];
}

- (void)recievedData:(NSData *)receiveData
{
    //保证数据操作线程安全
    @synchronized(self) {
        //解析返回的mes信息
        BRMessage *remoteMsg = [BRMessage messageWithPackageData:receiveData];
        NSMutableArray *array = [NSMutableArray array];
        [self.messageQueue enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            BRMessage *localMsg = obj;
            if (localMsg.cmd == remoteMsg.cmd-0x5000) {
                localMsg.responseMsg = [remoteMsg.msg copy];
                localMsg.isFinished = YES;
                localMsg.backDate = [NSDate date];
                [array addObject:localMsg];
            }
        }];
        //收到服务器后执行回调方法，通知发起地方，应该处理服务器响应了
        [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            BRMessage *localMsg = obj;
            [localMsg callResponseBlockAtOtherThread];
        }];
    }
}

#pragma mark - 时钟轮询 -
/**
 *  用于循环检测消息是否应该重发了
 */
- (void)loop
{
    @synchronized(self) {
        NSMutableArray *shouldDeleteArray = [NSMutableArray array];
        NSMutableArray *shouldRetryArray = [NSMutableArray array];
        [self.messageQueue enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            BRMessage *message = obj;
            if (message.isFinished) {
                [shouldDeleteArray addObject:message];
            }else
            {
                //还没有完成的消息
                double sendMilliSecond = [message.sendDate timeIntervalSince1970]*1000;
                double nowMilliSecond = [[NSDate date] timeIntervalSince1970] * 1000;
                //超过超时时间，发送消息
                if (message.retryCount<message.maxRetryCount) {
                    if ((nowMilliSecond - sendMilliSecond)>message.timeOut*1000) {
                        message.retryCount++;
                        [shouldRetryArray addObject:message];
                    }else
                    {
                        //不需要处理，继续等待知道服务器响应或超时
                    }
                }else
                {
                    [shouldDeleteArray addObject:message];
                }

            }
        }];
        
        //删除
        [self.messageQueue removeObjectsInArray:shouldDeleteArray];
        //重试
        [shouldRetryArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            BRMessage *message = obj;
            //回调正在重试
            [message callResponseBlockAtOtherThread];
            [self sendMessageObject:message];
            DLog(@"重试次数：%d",message.retryCount);
        }];
    }
}

-(void)startTimer{
    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
    _timer = [NSTimer scheduledTimerWithTimeInterval:kUDPLoopCheckRetryTime target:self selector:@selector(loop) userInfo:nil repeats:YES];
    [runLoop run];
}

-(void)stopTimer{
    // do something
    [_timer invalidate];
    _timer = nil;
}

#pragma mark - 收到服务器消息后并完成对消息的处理的通知 -
/**
 *  需要清除消息队列里面的消息，防止轮询再此请求
 *
 *  @param notification 通知
 */
- (void)finishOneMessageResponse:(NSNotification *) notification
{
    BRMessage *msg = notification.object;
    @synchronized(self) {
        [self.messageQueue removeObject:msg];
    }   
}

#pragma mark - 销毁 -
- (void)dealloc
{
    [self stopTimer];
}


@end
